﻿using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Architecture;
using demo.Extensions;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace XS.Tunnel.Infrastructure.Extensions
{
    public class TopoSurface
    {
        /// <summary>
        /// 创建地形，原有地形点按中心点进行偏移
        /// </summary>
        /// <param name="document"></param>
        /// <param name="points">地形点</param>
        /// <param name="center">中心点</param>
        /// <returns></returns>
        public static TopographySurface CreateTopograph(Document document, IList<XYZ> points, XYZ center)
        {
            IList<XYZ> points_Topo = new List<XYZ>();
            foreach (var item in points)
            {
                points_Topo.Add(Transform.CreateTranslation(center.Negate()).OfPoint(item));
            }
            TopographySurface topography;
            using (Transaction t = new Transaction(document))
            {
                t.Start("CreateTopography");
                topography = TopographySurface.Create(document, points_Topo);
                t.Commit();
            }
            return topography;
        }
        /// <summary>
        /// 复制原有地形，将原地形阶段但设为现有类型
        /// </summary>
        /// <param name="topography"></param>
        /// <returns></returns>
        public static TopographySurface SetBaseTopographSurface(TopographySurface topography)
        {
            TopographySurface surface;
            Document document = topography.Document;
            using (TopographyEditScope scope = new TopographyEditScope(document, "blah"))
            {
                scope.Start(topography.Id);
                using (Transaction trans = new Transaction(document))
                {
                    trans.Start("NewLab");
                    topography.CreatedPhaseId = document.Phases.get_Item(0).Id;
                    surface = document.GetElement(ElementTransformUtils.CopyElement(document, topography.Id, XYZ.Zero).First()) as TopographySurface;
                    trans.Commit();
                }
                scope.Commit(new FailurePrePreprocessor());
            }
            return surface;
        }
        /// <summary>
        /// 获取地形网格
        /// </summary>
        /// <param name="topography"></param>
        /// <returns></returns>
        public static Mesh GetMesh(TopographySurface topography)
        {
            Mesh mesh = null;
            GeometryElement geometryElement = topography.get_Geometry(new Options());
            foreach (var item in geometryElement)
            {
                if (item is Mesh)
                {
                    mesh = item as Mesh;
                    break;
                }
            }
            return mesh;
        }
        /// <summary>
      
        /// <summary>
        /// 清理子面域中的点并添加新的点集
        /// </summary>
        /// <param name="document"></param>
        /// <param name="subRegion"></param>
        /// <param name="points"></param>
        public static void ResetSiteSubRegion(Document document, SiteSubRegion subRegion, IList<XYZ> points)
        {
            TopographySurface sub = document.GetElement(subRegion.HostId) as TopographySurface;
            IList<XYZ> pointinside = subRegion.TopographySurface.GetInteriorPoints();
            using (TopographyEditScope editScope = new TopographyEditScope(document, "swa"))
            {
                editScope.Start(sub.Id);
                using (Transaction t = new Transaction(document))
                {
                    t.Start("Test");
                    if (pointinside.Count > 0)
                    { sub.DeletePoints(pointinside); }
                    sub.AddPoints(points);
                    t.Commit();
                }
                editScope.Commit(new FailurePrePreprocessor());
            }
        }
        /// <summary>
        /// 为地形添加点
        /// </summary>
        /// <param name="topography"></param>
        /// <param name="points"></param>
        public static void AddPoints(TopographySurface topography, IList<XYZ> points)
        {
            if (points.Count > 0)
            {
                Document document = topography.Document;
                using (TopographyEditScope editScope = new TopographyEditScope(document, "AddPoints"))
                {
                    editScope.Start(topography.Id);
                    using (Transaction t = new Transaction(document))
                    {
                        t.Start("AddPoints");
                        topography.AddPoints(points);
                        t.Commit();
                    }
                    editScope.Commit(new FailurePrePreprocessor());
                }
            }
        }
        /// <summary>
        /// 删除地形部分点
        /// </summary>
        /// <param name="topography"></param>
        /// <param name="points"></param>
        public static void DeletePoints(TopographySurface topography, IList<XYZ> points)
        {
            if (points.Count > 0)
            {
                Document document = topography.Document;
                using (TopographyEditScope editScope = new TopographyEditScope(document, "AddPoints"))
                {
                    editScope.Start(topography.Id);
                    using (Transaction t = new Transaction(document))
                    {
                        t.Start("AddPoints");
                        topography.DeletePoints(points);
                        t.Commit();
                    }
                    editScope.Commit(new FailurePrePreprocessor());
                }
            }

        }
        /// <summary>
        /// 生成子面域并清理范围内的点
        /// </summary>
        /// <param name="topography"></param>
        /// <param name="loop"></param>
        public static SiteSubRegion NewSiteSubRegion(TopographySurface topography, CurveLoop loop)
        {
            Document document = topography.Document;
            SiteSubRegion subRegion;
            IList<CurveLoop> loops = new List<CurveLoop>() { loop };
            using (Transaction t = new Transaction(document))
            {
                t.Start("AddPoints");
                subRegion = SiteSubRegion.Create(document, loops, topography.Id);
                t.Commit();
            }
            IList<XYZ> boundary = subRegion.TopographySurface.GetBoundaryPoints();
            IList<XYZ> interior = subRegion.TopographySurface.GetInteriorPoints();
            AddPoints(topography, boundary);
            DeletePoints(topography, interior);
            return subRegion;
        }
        /// <summary>
        /// 沿路径放样所形成的点，为地形添加生成的放样点时，地形应为平面且范围内无地形点
        /// </summary>
        /// <param name="sweep"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        public static IList<XYZ> GetSweepArcPoints(Curve sweep, double width, double height)
        {
            IList<XYZ> points_Topo = new List<XYZ>();
            XYZ point0 = new XYZ(-width / 2, 0, 0);
            XYZ point1 = new XYZ(width / 2, 0, 0);
            XYZ bottom = new XYZ(0, -height, 0);
            IList<XYZ> points = Arc.Create(point0, point1, bottom).Tessellate();
            double offset = 0.5;
            double length = sweep.Length - 2 * offset;
            for (int i = 0; i <= 10; i++)
            {
                double para = offset / sweep.Length + (double)i * length / (10 * sweep.Length);
                Transform transform = TransformUtils.GetTransform(sweep, para);
                foreach (var item in points)
                {
                    points_Topo.Add(transform.OfPoint(item));
                }
            }
            Transform trans1 = TransformUtils.GetTransform(sweep, 0);
            foreach (var item in points)
            {
                points_Topo.Add(new XYZ(trans1.OfPoint(item).X, trans1.OfPoint(item).Y, trans1.Origin.Z));
            }
            Transform trans2 = TransformUtils.GetTransform(sweep, 1);
            foreach (var item in points)
            {
                points_Topo.Add(new XYZ(trans2.OfPoint(item).X, trans2.OfPoint(item).Y, trans2.Origin.Z));
            }
            return points_Topo;
        }
        /// <summary>
        /// 判断两个三角形是否共边
        /// </summary>
        /// <param name="triangle1"></param>
        /// <param name="triangle2"></param>
        /// <returns></returns>
        public static bool IsCommonEdge(MeshTriangle triangle1, MeshTriangle triangle2)
        {
            bool isCommonEdge = false;
            IList<XYZ> points1 = new List<XYZ>() { triangle1.get_Vertex(0), triangle1.get_Vertex(1), triangle1.get_Vertex(2) };
            IList<XYZ> points2 = new List<XYZ>() { triangle2.get_Vertex(0), triangle2.get_Vertex(1), triangle2.get_Vertex(2) };
            int commonPoint = 0;
            foreach (var item1 in points1)
            {
                foreach (var item2 in points2)
                {
                    if (item1.IsAlmostEqualTo(item2))
                    {
                        commonPoint += 1;
                    }
                }
            }
            if (commonPoint == 2) { isCommonEdge = true; }
            return isCommonEdge;
        }
        /// <summary>
        /// 判断两个三角形是否相等
        /// </summary>
        /// <param name="triangle1"></param>
        /// <param name="triangle2"></param>
        /// <returns></returns>
        public static bool IsEqual(MeshTriangle triangle1, MeshTriangle triangle2)
        {
            bool isEqual = false;
            IList<XYZ> points1 = new List<XYZ>() { triangle1.get_Vertex(0), triangle1.get_Vertex(1), triangle1.get_Vertex(2) };
            IList<XYZ> points2 = new List<XYZ>() { triangle2.get_Vertex(0), triangle2.get_Vertex(1), triangle2.get_Vertex(2) };
            int commonPoint = 0;
            foreach (var item1 in points1)
            {
                foreach (var item2 in points2)
                {
                    if (item1.IsAlmostEqualTo(item2))
                    {
                        commonPoint += 1;
                    }
                }
            }
            if (commonPoint == 3) { isEqual = true; }
            return isEqual;
        }
        /// <summary>
        /// 获取标高处的边界为地形边界的Face，暂用于计算与边坡线的交点
        /// </summary>
        /// <param name="topography"></param>
        /// <param name="elevation"></param>
        /// <returns></returns>
        public static Face GetFaceAtElevation(TopographySurface topography, double elevation)
        {
            BoundingBoxXYZ bounding = topography.get_BoundingBox(topography.Document.ActiveView);
            XYZ max = bounding.Max;
            XYZ min = bounding.Min;
            Line start = Line.CreateBound(new XYZ(min.X, min.Y, elevation), new XYZ(min.X, max.Y, elevation));
            CurveLoop first = new CurveLoop(); first.Append(start);
            Line end = Line.CreateBound(new XYZ(max.X, min.Y, elevation), new XYZ(max.X, max.Y, elevation));
            CurveLoop second = new CurveLoop(); second.Append(end);
            IList<CurveLoop> loops = new List<CurveLoop>() { first, second };
            SolidOptions options = new SolidOptions(ElementId.InvalidElementId, ElementId.InvalidElementId);
            Solid solid = GeometryCreationUtilities.CreateLoftGeometry(loops, options);
            return solid.Faces.get_Item(0);
        }
    }

    public class FailurePrePreprocessor : IFailuresPreprocessor
    {
        public FailureProcessingResult PreprocessFailures(FailuresAccessor failuresAccessor)
        {
            return FailureProcessingResult.Continue;
        }
    }

}
